package com.ruoyi.pos.websocket;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.pos.domain.dto.device.response.DeviceDebugLogResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 设备调试WebSocket处理器
 * 
 * @author ruoyi
 * @date 2025-01-30
 */
@Component
public class DeviceDebugWebSocketHandler implements WebSocketHandler {

    private static final Logger logger = LoggerFactory.getLogger(DeviceDebugWebSocketHandler.class);

    // 存储WebSocket会话，按设备ID分组
    private final Map<Long, WebSocketSession> deviceSessions = new ConcurrentHashMap<>();
    
    // 存储管理员会话
    private final Map<String, WebSocketSession> adminSessions = new ConcurrentHashMap<>();

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        logger.info("WebSocket连接建立: {}", session.getId());
        
        // 从URI中获取设备ID或管理员标识
        String path = session.getUri().getPath();
        if (path.contains("/device/")) {
            // 设备连接
            Long deviceId = extractDeviceIdFromPath(path);
            if (deviceId != null) {
                deviceSessions.put(deviceId, session);
                logger.info("设备 {} 已连接WebSocket", deviceId);
            }
        } else {
            // 管理员连接
            adminSessions.put(session.getId(), session);
            logger.info("管理员已连接WebSocket");
        }
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        String payload = message.getPayload().toString();
        logger.info("收到WebSocket消息: {}", payload);

        try {
            // 解析消息
            Map<String, Object> messageData = objectMapper.readValue(payload, Map.class);
            String messageType = (String) messageData.get("type");
            
            switch (messageType) {
                case "DEBUG_COMMAND":
                    handleDebugCommand(session, messageData);
                    break;
                case "HEARTBEAT":
                    handleHeartbeat(session, messageData);
                    break;
                case "LOG_MESSAGE":
                    handleLogMessage(session, messageData);
                    break;
                default:
                    logger.warn("未知的消息类型: {}", messageType);
            }
        } catch (Exception e) {
            logger.error("处理WebSocket消息失败", e);
            sendErrorMessage(session, "消息处理失败: " + e.getMessage());
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        logger.error("WebSocket传输错误", exception);
        removeSession(session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        logger.info("WebSocket连接关闭: {}, 状态: {}", session.getId(), closeStatus);
        removeSession(session);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 处理调试指令
     */
    private void handleDebugCommand(WebSocketSession session, Map<String, Object> messageData) {
        try {
            Long deviceId = Long.valueOf(messageData.get("deviceId").toString());
            String command = (String) messageData.get("command");
            
            // 转发指令到对应设备
            WebSocketSession deviceSession = deviceSessions.get(deviceId);
            if (deviceSession != null && deviceSession.isOpen()) {
                Map<String, Object> commandMessage = new ConcurrentHashMap<>();
                commandMessage.put("type", "DEBUG_COMMAND");
                commandMessage.put("command", command);
                commandMessage.put("timestamp", System.currentTimeMillis());
                commandMessage.put("sender", "admin");
                deviceSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(commandMessage)));
                
                // 通知管理员指令已发送
                sendSuccessMessage(session, "调试指令已发送到设备 " + deviceId);
            } else {
                sendErrorMessage(session, "设备 " + deviceId + " 未连接");
            }
        } catch (Exception e) {
            logger.error("处理调试指令失败", e);
            sendErrorMessage(session, "发送调试指令失败: " + e.getMessage());
        }
    }

    /**
     * 处理心跳消息
     */
    private void handleHeartbeat(WebSocketSession session, Map<String, Object> messageData) {
        try {
            Map<String, Object> response = new ConcurrentHashMap<>();
            response.put("type", "HEARTBEAT_RESPONSE");
            response.put("timestamp", System.currentTimeMillis());
            response.put("status", "ok");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        } catch (Exception e) {
            logger.error("处理心跳消息失败", e);
        }
    }

    /**
     * 处理日志消息
     */
    private void handleLogMessage(WebSocketSession session, Map<String, Object> messageData) {
        try {
            // 广播日志消息给所有管理员
            broadcastToAdmins(messageData);
        } catch (Exception e) {
            logger.error("处理日志消息失败", e);
        }
    }

    /**
     * 向所有管理员广播消息
     */
    public void broadcastToAdmins(Object message) {
        try {
            String messageJson = objectMapper.writeValueAsString(message);
            adminSessions.values().removeIf(session -> {
                try {
                    if (session.isOpen()) {
                        session.sendMessage(new TextMessage(messageJson));
                        return false;
                    }
                } catch (IOException e) {
                    logger.error("发送消息到管理员失败", e);
                }
                return true;
            });
        } catch (Exception e) {
            logger.error("广播消息失败", e);
        }
    }

    /**
     * 向指定设备发送消息
     */
    public void sendToDevice(Long deviceId, Object message) {
        try {
            WebSocketSession deviceSession = deviceSessions.get(deviceId);
            if (deviceSession != null && deviceSession.isOpen()) {
                String messageJson = objectMapper.writeValueAsString(message);
                deviceSession.sendMessage(new TextMessage(messageJson));
            }
        } catch (Exception e) {
            logger.error("发送消息到设备失败", e);
        }
    }

    /**
     * 发送成功消息
     */
    private void sendSuccessMessage(WebSocketSession session, String message) {
        try {
            Map<String, Object> response = new ConcurrentHashMap<>();
            response.put("type", "SUCCESS");
            response.put("message", message);
            response.put("timestamp", System.currentTimeMillis());
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        } catch (Exception e) {
            logger.error("发送成功消息失败", e);
        }
    }

    /**
     * 发送错误消息
     */
    private void sendErrorMessage(WebSocketSession session, String message) {
        try {
            Map<String, Object> response = new ConcurrentHashMap<>();
            response.put("type", "ERROR");
            response.put("message", message);
            response.put("timestamp", System.currentTimeMillis());
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        } catch (Exception e) {
            logger.error("发送错误消息失败", e);
        }
    }

    /**
     * 从路径中提取设备ID
     */
    private Long extractDeviceIdFromPath(String path) {
        try {
            String[] parts = path.split("/");
            for (int i = 0; i < parts.length - 1; i++) {
                if ("device".equals(parts[i]) && i + 1 < parts.length) {
                    return Long.valueOf(parts[i + 1]);
                }
            }
        } catch (Exception e) {
            logger.error("提取设备ID失败", e);
        }
        return null;
    }

    /**
     * 移除会话
     */
    private void removeSession(WebSocketSession session) {
        deviceSessions.values().removeIf(s -> s.getId().equals(session.getId()));
        adminSessions.remove(session.getId());
    }

    /**
     * 获取在线设备数量
     */
    public int getOnlineDeviceCount() {
        return deviceSessions.size();
    }

    /**
     * 获取在线管理员数量
     */
    public int getOnlineAdminCount() {
        return adminSessions.size();
    }
}
